package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.dto.SearchDataInConditionDTO;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.pojo.ItemDataPoJo;
import com.xbongbong.paas.pojo.vo.SearchDataInConditionVO;
import com.xbongbong.paas.service.ConditionListService;
import com.xbongbong.paas.service.DistinctDataService;
import com.xbongbong.paas.service.ProFormDataService;
import com.xbongbong.paas.service.impl.base.BaseFormDataService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.DataUtil;
import com.xbongbong.paas.util.ItemUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formexplain.pojo.ConditionExplainPojo;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.model.impl.IndexTypeModelImpl;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import static com.xbongbong.paas.elasticsearch.constant.EsNormalConstant.MINI_MUM_SHOULD_MATCH;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author 吴峰
 * @version v1.0
 * @date 2020/4/8 19:43
 * @since v1.0
 */
@Service("conditionListService")
public class ConditionListServiceImpl implements ConditionListService {

    private static final Logger LOG = LoggerFactory.getLogger(DistinctDataServiceImpl.class);

    private static final String UNDERLINE = "_";

    @Resource
    private DistinctDataService distinctDataService;
    @Resource
    private BaseFormDataService baseFormDataService;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private ProFormDataService proFormDataService;
    @Resource
    private IndexTypeModelImpl indexTypeModel;

    @Override
    public SearchDataInConditionVO listOfText(ConditionExplainPojo conditionExplainPojo, FieldAttrEntity fieldAttrEntity, SearchDataInConditionDTO searchDataInConditionDTO, FieldTypeEnum fieldTypeEnum) throws XbbException {
        SearchDataInConditionVO searchDataInConditionVO = new SearchDataInConditionVO();
        try {
            // 模糊查询 类似于sql中的like
            Object conditionValue = searchDataInConditionDTO.getValue();
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            //解析查询条件
            boolQueryBuilder.filter(termQuery("corpid.keyword", searchDataInConditionDTO.getCorpid()));
            if (!Objects.equals(searchDataInConditionDTO.getBusinessType(), XbbRefTypeEnum.DISTRIBUTOR_ACCOUNT.getCode())) {
                if (searchDataInConditionDTO.getLimitForms()){
                    boolQueryBuilder.filter(termsQuery("formId", searchDataInConditionDTO.getFormIdList()));
                }else {
                    boolQueryBuilder.filter(termQuery("formId", searchDataInConditionDTO.getFormId()));
                }
            }
            IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(searchDataInConditionDTO.getCorpid(), searchDataInConditionDTO.getBusinessType(), searchDataInConditionDTO.getSaasMark());

            boolQueryBuilder.filter(termQuery("del", searchDataInConditionDTO.getDel()));
            EsUtil.parseCondition(boolQueryBuilder,searchDataInConditionDTO.getConditionsList(),"",searchDataInConditionDTO.getCorpid(),searchDataInConditionDTO.getBusinessType());
            EsUtil.parseShouldCondition(boolQueryBuilder,searchDataInConditionDTO.getShouldConditionsList(),"",searchDataInConditionDTO.getCorpid(),searchDataInConditionDTO.getBusinessType());
            // 共享权限
            EsUtil.parseSharePermissionCondition(boolQueryBuilder, searchDataInConditionDTO.getSharePermission(), searchDataInConditionDTO.getCorpid(), searchDataInConditionDTO.getBusinessType(), false);
            distinctDataService.productCondition(boolQueryBuilder,searchDataInConditionDTO.getBusinessType(),searchDataInConditionDTO.getSubBusinessType(),fieldAttrEntity.getAttr());
            String subAttr = searchDataInConditionDTO.getSubAttr();
            String attr = searchDataInConditionDTO.getAttr();

            if(conditionValue != null && StringUtil.isNotEmpty(conditionValue.toString())){
                String name;
                if(StringUtil.isNotEmpty(subAttr)){
                    name = "data." + attr + "." + subAttr;
                }else {
                    name = "data."+attr;
                }
                QueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery(name, searchDataInConditionDTO.getValue());
                BoolQueryBuilder shouldBool = boolQuery();
                shouldBool.should(queryBuilder);
                shouldBool.should(termQuery(name + StringConstant.POINT + StringConstant.KEY_WORD, searchDataInConditionDTO.getValue()));
                shouldBool.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
                boolQueryBuilder.filter(shouldBool);
            }
            String field;
            String name = "";
            if(StringUtil.isNotEmpty(subAttr)){
                field = attr+ "." +subAttr;
            }else{
                field = attr;
            }
            if(FieldTypeEnum.TEXT.getEsalias().equals(attr.split(UNDERLINE)[0]) || FieldTypeEnum.TEXT.getEsalias().equals(subAttr.split(UNDERLINE)[0])
                    || FieldTypeEnum.SERIALNO.getAlias().equals(attr) || FieldTypeEnum.TEXT.getAlias().equals(subAttr)){
                name = "data."+ field + ".keyword";
            }
            if (Objects.equals(searchDataInConditionDTO.getBusinessType(), XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode()) || Objects.equals(searchDataInConditionDTO.getBusinessType(), XbbRefTypeEnum.WORK_ORDER_OUTSTOCK.getCode())) {
                field = "data." + field;
            }
            if (!conditionExplainPojo.getIsSubForm()) {
                boolQueryBuilder.filter(existsQuery(name.replace(".keyword", "")));
                boolQueryBuilder.mustNot(termQuery(name, ""));
            }
            nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
            NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            //设置查询条件
            sourceBuilder.query(searchQuery.getQuery());

            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, indexTypeEnum.getType()));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(field);
            sourceBuilder.sort(new FieldSortBuilder(FieldTypeEnum.UPDATETIME.getAlias()).order(SortOrder.DESC));
            List<PaasFormDataEntityExt> dataList = paasEsModel.list(sourceBuilder, indexTypeEnum, fieldList, 1, 10);
            if (dataList == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            if (Objects.equals(conditionExplainPojo.getParentFieldAttr().getFieldType(), FieldTypeEnum.SUB_FORM.getType())) {
                proFormDataService.setSubFormData(dataList, searchDataInConditionDTO.getCorpid(), searchDataInConditionDTO.getSaasMark(), searchDataInConditionDTO.getBusinessType(), searchDataInConditionDTO.getFormId());
            }
            List<ItemDataPoJo> list = getItemData(searchDataInConditionDTO, dataList, fieldAttrEntity);

            searchDataInConditionVO.setItems(DataUtil.filterRepetition(list));
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("conditionListService.listOfText检索文本字段出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return searchDataInConditionVO;
    }

    private List<ItemDataPoJo> getItemData(SearchDataInConditionDTO searchDataInConditionDTO, List<PaasFormDataEntityExt> dataList, FieldAttrEntity fieldAttrEntity) throws XbbException{
        List<ItemDataPoJo> list = new ArrayList<>();
        Object searchValue = searchDataInConditionDTO.getValue();
        for (PaasFormDataEntityExt paasFormDataEsEntity: dataList) {
            JSONObject data = paasFormDataEsEntity.getData();
            if (Objects.isNull(data)) {
                continue;
            }
            Iterator iterator = data.keySet().iterator();
            while (iterator.hasNext()){
                ItemDataPoJo itemDataPoJo = new ItemDataPoJo();
                String key = iterator.next().toString();
                if (key.equals(searchDataInConditionDTO.getAttr())) {
                    if(StringUtil.isNotEmpty(searchDataInConditionDTO.getSubAttr())){
                        // 子表单逻辑
                        JSONArray subDataArray = data.getJSONArray(key);
                        for(int i=0; i<subDataArray.size(); i++) {
                            JSONObject subDataObject = subDataArray.getJSONObject(i);
                            Iterator subIterator = subDataObject.keySet().iterator();
                            while (subIterator.hasNext()){
                                ItemDataPoJo subItemDataPoJo = new ItemDataPoJo();
                                String  subKey = subIterator.next().toString();
                                if(subKey.equals(searchDataInConditionDTO.getSubAttr())){
                                    Object value = subDataObject.get(subKey);
                                    Object text = ItemUtil.getText(value, fieldAttrEntity);
                                    if (Objects.isNull(text)) {
                                        continue;
                                    }
                                    if (Objects.nonNull(searchValue) && searchValue.toString().contains(text.toString())) {
                                        subItemDataPoJo.setText(text);
                                        subItemDataPoJo.setValue(value);
                                        list.add(subItemDataPoJo);
                                    } else if (Objects.isNull(searchValue) || StringUtil.isEmpty(searchValue.toString())) {
                                        subItemDataPoJo.setText(text);
                                        subItemDataPoJo.setValue(value);
                                        list.add(subItemDataPoJo);
                                    }
                                }
                            }
                        }
                    }else {
                        Object value = data.get(key);
                        Object text = ItemUtil.getText(value, fieldAttrEntity);
                        if (Objects.isNull(text)) {
                            continue;
                        }
                        itemDataPoJo.setText(text);
                        itemDataPoJo.setValue(value);
                        list.add(itemDataPoJo);
                    }
                }
            }
        }
        Boolean isCombo = Objects.equals(FieldTypeEnum.COMBO.getType(), fieldAttrEntity.getFieldType())
                || Objects.equals(FieldTypeEnum.COMBO_CHECK.getType(), fieldAttrEntity.getFieldType());
        if (isCombo) {
            ConditionExplainPojo conditionExplainPojo = baseFormDataService.getFieldAttr(searchDataInConditionDTO);
            Boolean subAttrFlag = false;
            fieldAttrEntity = conditionExplainPojo.getParentFieldAttr();
            if (StringUtil.isNotEmpty(searchDataInConditionDTO.getSubAttr())) {
                subAttrFlag = true;
                fieldAttrEntity = conditionExplainPojo.getSubFieldAttr();
            }
            List<ItemDataPoJo> itemDataList = baseFormDataService.getCustomList(searchDataInConditionDTO, fieldAttrEntity, subAttrFlag, conditionExplainPojo);
            itemDataList.forEach(item->{
                item.setText(item.getText()+"（自定义）");
            });
            list.addAll(itemDataList);
        }
        return list;
    }
}
